Kaggle竞赛(一)预测泰坦尼克号幸存者 数据导入和预处理

在注册完Kaggle账号后,我们就可以来试一试Kaggle上最简单的分类问题,利用当年泰坦尼克号乘客的个人信息来预测他们其中的幸存者。

下载数据集

进入Kaggle Titanic页面下载数据集,我们可以看到这里有三个csv文件

  • train.csv是我们训练用数据,我们将使用这些数据建模
  • test.csv是测试用数据,我们将用这些数据检验模型的准确度
  • gender_submossion.csv提供给我们知道最后应该提交什么样子的文件

导入数据集

我个人习惯用Jupyter Notebook,它可以直接生成markdown模式。可以直接安装anaconda,里面就包括了Jupyter Notebook。我们要做的是首先打开Jupyter Notebook,然后在数据集同个目录里新建一个Python notebook。然后正式开始我们的代码:

1
2
3
4
5
# 导入几个基本库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

1
2
df=pd.read_csv('train.csv')
df.head()

我们看到这个数据集包括:

  1. PassengerId,乘客的序号,从第一位开始到最后一位乘客
  2. Survived,0表示该乘客死亡,1表示生还
  3. Pclass,从1到3分别表示该乘客搭乘一等舱、二等舱、三等舱
  4. Name,乘客的姓名,格式是:名,称谓.姓氏
  5. Sex,乘客的性别,female女,male男
  6. Age,乘客的年龄
  7. SibSp,该乘客的兄弟姐妹和配偶也在船上的数量
  8. Parch,该乘客的父母和子女也在船上的数量
  9. Ticket,票号
  10. Fare,票价
  11. Cabin,客舱号
  12. Embarked,登船港口,C = Cherbourg, Q = Queenstown, S = Southampton

几个基本的分析

训练集统计

1
df.count()

PassengerId    891
Survived       891
Pclass         891
Name           891
Sex            891
Age            714
SibSp          891
Parch          891
Ticket         891
Fare           891
Cabin          204
Embarked       889
dtype: int64

我们可以看到在训练集train.csv里一共891名乘客,其中Age,Cabin,Embarked不全,为了模型的准确度,我们最好想办法补全它们。

总体生还率

1
df['Survived'].mean()

0.3838383838383838

总体生还率是38.38%

按照客舱等级分组

1
2
calss_grouping=df.groupby('Pclass').mean()
calss_grouping

<img src="http://ww1.sinaimg.cn/mw690/b66c02d5gy1fn49fz3neqj20d003tdga.jpg"/>

我们看到客舱越高级,生还率越高,有钱真好...

按客舱等级加性别分组

1
2
class_sex_grouping = df.groupby(['Pclass','Sex']).mean()
class_sex_grouping

<img src="http://ww1.sinaimg.cn/mw690/b66c02d5gy1fn49intgf2j20ew0630to.jpg"/>

1
class_sex_grouping['Survived'].plot.bar()

每个客舱等级里女性生还几率较大,还是比较绅士的。

按年龄层分组

1
2
3
group_by_age = pd.cut(df["Age"], np.arange(0, 90, 10))
age_grouping = df.groupby(group_by_age).mean()
age_grouping['Survived'].plot.bar()

貌似年轻的生还几率比较大。

测试集统计

1
2
df_test=pd.read_csv('test.csv')
df_test.count()

PassengerId    418
Pclass         418
Name           418
Sex            418
Age            332
SibSp          418
Parch          418
Ticket         418
Fare           417
Cabin           91
Embarked       418
dtype: int64

测试集的数据缺失发生在Age,Fare和Cabin上,和训练集并不一样,这点要注意。

处理缺失数据

处理年龄

1
2
3
# 不同称谓的年龄中位数
title_age_grouping=df[['Title','Age']].groupby('Title').median()
title_age_grouping.plot.bar()

1
2
3
4
5
6
# 补全年龄的函数
def fill_ages(df,title_age_grouping):
for i in range(len(df.index)):
for j in range(len(title_age_grouping.index)):
if df.loc[i,'Title'] == title_age_grouping.index[j] and np.isnan(df.loc[i,'Age']):
df.loc[i,'Age']=title_age_grouping.Age[j]

处理票价

1
2
3
# 不同客舱等级和称谓的票价中位数
class_title_fare_grouping=df[['Pclass','Title','Fare']].groupby(['Pclass','Title']).median()
class_title_fare_grouping.plot.bar()

1
2
3
4
5
6
# 补全票价的函数
def fill_fares(df,class_title_fare_grouping):
for i in range(len(df.index)):
for j in range(len(class_title_fare_grouping.index)):
if (df.loc[i,'Pclass'], df.loc[i,'Title'])== class_title_fare_grouping.index[j] and np.isnan(df.loc[i,'Fare']):
df.loc[i,'Fare']=class_title_fare_grouping.Fare[j]

最后总体处理

  1. 把上面的补全年龄和票价的函数用在数据集上,
  2. 先将'Cabin'列drop掉,因为缺少很多数据,并且我没想到怎么样补全客舱数据,
  3. 将缺少数据的行用df.dropna()清理掉,
  4. 再将无用的行'PassengerId','Name','Ticket'列drop掉,
  5. 编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from sklearn import preprocessing

def preprocess_titanic_df(df,title_age_grouping,class_title_fare_grouping):
#copy
processed_df = df.copy()
#get titles
get_titles(processed_df)
#fill missing ages
fill_ages(processed_df,title_age_grouping)
#fill missing fares
fill_fares(processed_df,class_title_fare_grouping)
#drop cabin variable
processed_df = processed_df.drop(['Cabin'], axis=1)
#drop na
processed_df = processed_df.dropna()
#label encoder
le = preprocessing.LabelEncoder()
processed_df.Sex = le.fit_transform(processed_df.Sex)
processed_df.Embarked = le.fit_transform(processed_df.Embarked)
processed_df.Title = le.fit_transform(processed_df.Title)
processed_df = processed_df.drop(['PassengerId','Name','Ticket'],axis=1)
return processed_df

1
2
processed_df = preprocess_titanic_df(df,title_age_grouping,class_title_fare_grouping)
processed_df.count()

Survived    889
Pclass      889
Sex         889
Age         889
SibSp       889
Parch       889
Fare        889
Embarked    889
Title       889
dtype: int64

最后将训练集分成80%的训练集train和20%的验证集test,注意区分这里的验证集test是已知结果的,用来验证比较各种模型。最后我们还有test.csv是未知结果的,用来最后验证准确度。

1
2
3
4
5
6
7
8
9
10
11
from sklearn import model_selection

X = processed_df.drop(['Survived'], axis=1).values
y = processed_df['Survived'].values

X_train, X_test, y_train, y_test = model_selection.train_test_split(X,y,test_size=0.2)

print('X_train',X_train.shape)
print('y_train',y_train.shape)
print('X_test',X_test.shape)
print('y_test',y_test.shape)

X_train (711, 8)
y_train (711,)
X_test (178, 8)
y_test (178,)

现在数据预处理已经完成,下一步正式进入机器学习分类算法。